package com.ipan.jfinal.tdo.transform;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ipan.kits.base.ReUtil;
import com.ipan.kits.collection.MapUtil;
import com.ipan.kits.io.FileUtil;
import com.ipan.kits.io.ResourceUtil;

/**
 * 转换器工具
 * 
 * @author iPan
 * @date 2022-01-26
 */
public class TransducerUtil {
	
	private static Logger LOG = LoggerFactory.getLogger(TransducerUtil.class);
	
	/**
	 * 线程本地变量
	 * 存放系统插值、日期时间格式化（列->格式）
	 */
	private static ThreadLocal<Map<String, String>> LOCAL_MAP = new ThreadLocal<Map<String, String>>() {
		@Override
		protected Map<String, String> initialValue() {
			return new HashMap<String, String>();
		}
	};

	private static final String ALL_PATTERN = "^(format|dict|merge|define|#)\\{(.+)\\}$";
	private static final String FORMAT_PATTERN = "^format\\{.+\\}$";
	private static final String DICT_PATTERN = "^dict\\{.+\\}$";
	// merge{1,2}、merge{1,2,3}、merge{ 1, 2 ,3 }、merge{1,2,3,' '}、merge{ 1, 2 ,3, '-'}...
	private static final String MERGE_PATTERN = "^merge\\{\\s*\\d+\\s*,\\s*\\d+\\s*(\\s*,\\s*\\d+\\s*)*(\\s*,\\s*'.*'\\s*)*\\}$";
	private static final String DEFINE_PATTERN = "^define\\{.+\\}$";
	private static final String INSERT_PATTERN = "^#\\{.+\\}$";
	private static final String CLEAR_MONEY_PATTERN = "clearMoney";
	private static final String CLEAR_PCT_PATTERN = "clearPct";
	
	// 暂对毫秒的支持仅支持3位，3位以上直接截取掉；
	private static final String CUT_MILLISECOND_PAT1 = "^\\d{18,20}$";
	private static final String CUT_MILLISECOND_PAT2 = "^.*\\d{1,2}(:|\\.)\\d{1,2}(:|\\.)\\d{1,2}\\.\\d{4,6}$";
	
	private static final BigDecimal HUNDRED = new BigDecimal(100);
	
	public static boolean isValid(String line) {
		return Pattern.matches(ALL_PATTERN, line);
	}
	public static boolean isFormatPattern(String line) {
		return Pattern.matches(FORMAT_PATTERN, line);
	}
	public static boolean isDictPattern(String line) {
		return Pattern.matches(DICT_PATTERN, line);
	}
	public static boolean isMergePattern(String line) {
		return Pattern.matches(MERGE_PATTERN, line);
	}
	public static boolean isDefinePattern(String line) {
		return Pattern.matches(DEFINE_PATTERN, line);
	}
	public static boolean isInsertPattern(String line) {
		return Pattern.matches(INSERT_PATTERN, line);
	}
	public static boolean isClearMoneyPattern(String line) {
		return CLEAR_MONEY_PATTERN.equals(line);
	}
	public static boolean isClearPctPattern(String line) {
		return CLEAR_PCT_PATTERN.equals(line);
	}
	
	public static String getFormatBody(String line) {
		return ReUtil.get(ALL_PATTERN, line, 2);
	}
	
	public static Map<String, String> formatBodyToMap(String formatBody) {
		if (StringUtils.isBlank(formatBody)) {
			return MapUtil.emptyMap();
		}
		String[] arr = formatBody.trim().split(";");
		Map<String, String> map = MapUtil.newHashMapWithCapacity(arr.length, MapUtil.DEFAULT_LOAD_FACTOR);
		for (String item : arr) {
			String[] kv = item.split("=");
			if (StringUtils.isNotBlank(kv[0])) map.put(kv[0], kv[1]);
		}
		return map;
	}
	
	public static String nullToEmpty(String str) {
		return (str == null) ? "" : str;
	}
	
	/**
	 * 清除货币格式化（会清除正负号、括号）
	 * 
	 * Excel格式"￥"#,##0.00_);("￥"#,##0.00)，负数转换会带()。
	 */
	public static String clearMoney(String str) {
		if (StringUtils.isBlank(str)) {
			return "";
		}
		return str.replaceAll("[$\\+\\-￥\\(\\), \\s]", "");
	}
	
	/**
	 * 清除百分数
	 */
	public static String clearPct(String str) {
		if (StringUtils.isBlank(str)) {
			return "";
		}
		str = str.replaceAll("[, \\s]", "");
		String regex = "^\\s*(\\d+(\\.\\d*)*)\\s*%\\s*$";
		String strNum = nullToEmpty(ReUtil.get(regex, str, 1)).trim();
		if (StringUtils.isBlank(strNum)) {
			return "";
		}
		return new BigDecimal(strNum).divide(HUNDRED).toString();
	}
	
	/**
	 * 添加线程本地缓存
	 * 将系统插值、日期时间对应的列的匹配格式存入该缓存；
	 */
	public static void putLocalValue(String key, String value) {
		LOCAL_MAP.get().put(key, value);
	}
	/**
	 * 获取线程本地缓存
	 */
	public static String getLocalValue(String key) {
		return LOCAL_MAP.get().get(key);
	}
	public static String getLocalValueFillNull(String key) {
		String val = LOCAL_MAP.get().get(key);
		return (val == null) ? "" : val;
	}
	/**
	 * 清除线程本地缓存
	 */
	public static void removeLocalValue() {
		LOCAL_MAP.remove();
	}
	
	
	// -- 日期时间格式处理 -- //
	private static final String DATEFORMAT_CONFIG_PATH = "dateFormatConfig.txt"; // 项目中使用可以在项目里面替换这个配置文件
	private static Map<String, String> _DATEFORMAT_CONFIG = new LinkedHashMap<String, String>();
	public static Map<String, String> getDataFormatConfig() {
		if (_DATEFORMAT_CONFIG.size() > 0) {
			return _DATEFORMAT_CONFIG;
		}
		synchronized (_DATEFORMAT_CONFIG) {
			if (_DATEFORMAT_CONFIG.size() > 0) {
				return _DATEFORMAT_CONFIG;
			}
			loadConfig();
		}
		return _DATEFORMAT_CONFIG;
	}
	
	public static void loadConfig() {
		synchronized (_DATEFORMAT_CONFIG) {
			URL url = null;
			try {
				// 加载配置文件
				url = ResourceUtil.asUrl(DATEFORMAT_CONFIG_PATH);
				
			} catch (Exception e) {
				LOG.info("读取配置文件" + DATEFORMAT_CONFIG_PATH + "出错，系统开始加载默认配置。", e);
				url = ResourceUtil.asUrl(TransducerUtil.class, DATEFORMAT_CONFIG_PATH);
			};
			try {
				File file = new File(url.getFile());
				FileUtil.toLines(file).stream().filter(line -> {
					if (line == null) return false;
					line = line.trim();
					if (StringUtils.isBlank(line) || line.startsWith("#")) {
						return false;
					}
					return true;
				}).forEach(item -> {
					String[] arr = item.split("=");
					String key = arr[0].trim();
					String value = arr[1].trim();
					_DATEFORMAT_CONFIG.put(key, value);
				});
			} catch (IOException e) {
				LOG.info("加载配置文件" + DATEFORMAT_CONFIG_PATH + "出错。", e);
			}
		}
	}
	
	/**
	 * 自动扫描字符串的日期时间格式
	 */
	public static String autoScan(String cellIndex, String line) {
		if (StringUtils.isBlank(line)) {
			return null;
		}
		Map<String, String> config = getDataFormatConfig();
		Iterator<String> iter = config.keySet().iterator();
		String dateFormat = null;
		while (iter.hasNext()) {
			String regex = iter.next();
			if (Pattern.matches(regex, line)) {
				dateFormat = config.get(regex);
				putLocalValue(cellIndex.toString(), dateFormat); // 缓存到本地
				LOG.info("Date类型自动匹配，第{}列{}匹配{}。", cellIndex, line, dateFormat);
				break;
			}
		}
		return dateFormat;
	}
	public static String getDateFormatByCellIndex(String cellIndex) { // 仅从缓存获取
		String dateFormat = getLocalValue(cellIndex.toString());
		return dateFormat;
	}
	public static String autoGetDateFormat(String cellIndex, String cellValue) { // 先从缓存获取，然后自动扫描；
		String dateFormat = getLocalValue(cellIndex.toString()); // 从缓存获取
		if (StringUtils.isBlank(dateFormat)) {
			dateFormat = autoScan(cellIndex, cellValue);
			if (StringUtils.isBlank(dateFormat)) {
				LOG.warn("无法识别的Date类型{}", cellValue);
			}
		}
		return dateFormat;
	}
	
	/**
	 * 截取毫秒超过3位的时间字符串
	 * 示例：
	 * 	11:00:10.111111				=> 11:00:10.111
	 * 	2022-02-25 11:00:10.111111	=> 2022-02-25 11:00:10.111
	 * 	20220225110010111111		=> 20220225110010111
	 * 
	 *  11:00:10.1					=> 11:00:10.1
	 * 	2022-02-25 11:00:10.1		=> 2022-02-25 11:00:10.1
	 * 	202202251100101				=> 202202251100101
	 * 
	 *  11:00:10					=> 11:00:10
	 * 	2022-02-25 11:00:10			=> 2022-02-25 11:00:10
	 * 	20220225110010				=> 20220225110010
	 * 
	 * 注意：不足三位的毫秒转换以后会在前面补0，比如.1 => .001；
	 */
	public static String autoCutDateMsecValue(String dateValue) {
		if (dateValue == null) return dateValue;
		try {
			if (Pattern.matches(CUT_MILLISECOND_PAT1, dateValue)) {
				return dateValue.substring(0, 17);
			} else if (Pattern.matches(CUT_MILLISECOND_PAT2, dateValue)) {
				int index = dateValue.lastIndexOf(".");
				String msStr = dateValue.substring(index + 1, index + 4);
				String newStr = dateValue.substring(0, index + 1) + msStr;
				return newStr;
			} else {
				return dateValue;
			}
		} catch(Exception e) {
			LOG.error("转换Date格式失败", e);
			return dateValue;
		}
	}
	
	//-- 另外字典的配置 --//
//	/**
//	 * 获取另外（配置模板以外）的字典配置——收付标志
//	 */
//	public static Map<String, String> getTransformDictSfbz() {
//		// 加载配置文件
//		Map<String, String> map = new HashMap<String, String>();
//		String otherdictName = "other-dict.txt";
//		PropKit.useless(otherdictName);
//		Prop prop = PropKit.use(otherdictName);
//		String line = prop.get("transform.dict.sfbz"); // 风险预警数据——收付标志
//		String[] arr = line.split(";");
//		for (String item : arr) {
//			String[] vals = item.split("=");
//			map.put(vals[0].trim(), vals[1].trim());
//		}
//		return map;
//	}
//	
//	public static void main(String[] args) {
//		loadConfig();
//	}
}
